//
//  AlinkManager.m
//  JomooCloudApp
//
//  Created by chewyong on 2018/7/28.
//

#import "AlinkManager.h"
#import <AlinkAppExpress/LKAppExpress.h>
#import <IMSAuthentication/IMSAuthentication.h>
#import <AlinkAppExpress/LKAppExpress.h>
#import <IMSApiClient/IMSApiClient.h>
#import <AlinkAppExpress/LKAppExpressEnvSet.h>

#define NOT_DEVICE_EDIT_SUCCESS @"keyOfDviceeEditSuccess"
#define UPDATE_FILTER_SUCCESS @"UPDATE_FILTER_SUCCESS"
#define ALITHING_EVENT_NOTIFY @"ALITHING_EVENT_NOTIFY"
#define ALITHING_EVENT_ONDOWNSTREAM @"ALITHING_EVENT_ONDOWNSTREAM"

#pragma mark -

#ifndef weakify
    #if DEBUG
        #if __has_feature(objc_arc)
            #define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
        #else
            #define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
        #endif
    #else
        #if __has_feature(objc_arc)
            #define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
        #else
            #define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
        #endif
    #endif
#endif


#ifndef strongify
    #if DEBUG
        #if __has_feature(objc_arc)
            #define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
        #else
            #define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
        #endif
    #else
        #if __has_feature(objc_arc)
            #define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
        #else
            #define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
        #endif
    #endif
#endif

static AlinkManager *sharedInstance = nil;

@interface AlinkManager () {
    BOOL isBinded;
}
@end

@implementation AlinkManager

static dispatch_once_t onceToken;

+ (instancetype)shareManager {
    dispatch_once(&onceToken, ^{
      sharedInstance = [[self alloc] init];
    });

    return sharedInstance;
}

+ (void)attempDealloc {
    if (sharedInstance) {
        onceToken = 0;
        sharedInstance = nil;
    }
}

- (id)init {
    self = [super init];
    if (self) {
        [self initAlink];

        //[self addNotifications];
    }

    return self;
}

- (void)initAlink {
    [LKAppExpressEnvSet setRunEnv:LKAppExpressEnvRelease];

    config = [[LKAEConnectConfig alloc] init];
    config.appKey = [IMSConfiguration sharedInstance].appKey;
    config.authCode = [IMSConfiguration sharedInstance].authCode;
    [[LKAppExpress sharedInstance] startConnect:config connectListener:self];

    //IMSConfiguration * imsconfig = [IMSConfiguration sharedInstance];
    //LKAEConnectConfig * config = [LKAEConnectConfig new];
    //config.appKey = imsconfig.appKey;
    //config.authCode = imsconfig.authCode;
    //指定长连接服务器地址。 （默认不填，SDK会使用默认的地址及端口。默认为国内华东节点。不要带 "协议://"，如果置为空，底层通道会使用默认的地址）
    //config.server = @""
    //开启动态选择Host功能。 (默认 NO，海外环境请设置为 YES。此功能前提为 config.server 不特殊指定。）
    //config.autoSelectChannelHost = NO;
    //[[LKAppExpress sharedInstance]startConnect:config connectListener:self];
    //self 需要实现 LKAppExpConnectListener 接口
    [[LKAppExpress sharedInstance] addDownStreamListener:YES listener:self];

    [self bindAccountWithChannel];
}

- (void)analyzeDeviceData:(NSDictionary *)dic {
    //NSDictionary *params = [dic objectForKey:@"params"];

    //NSString *deviceName = [dic objectForKey:@"deviceName"];
    //NSDictionary *items = [dic objectForKey:@"items"];
    //for (NSString *key in items.allKeys) {
    //    NSDictionary *valueDic = [items objectForKey:key];
    //    id value = [valueDic objectForKey:@"value"];
    //    NSLog(@"%@ %@ : %@",deviceName,key,value);
    //}
    if (dic) {
        if (_baseDataReturnBlock) {
            _baseDataReturnBlock(dic);
        }
        if (_waterSafetyReturnBlock) {
            _waterSafetyReturnBlock(dic);
        }
        if (_bathtubBlock) {
            _bathtubBlock(dic);
        }
        if (_toiletBlock) {
            _toiletBlock(dic);
        }
        if (_clothesStandBlock) {
            _clothesStandBlock(dic);
        }
        if (_drySteamRoomBlock) {
            _drySteamRoomBlock(dic);
        }
        if (_smokeAlarmBlock) {
            _smokeAlarmBlock(dic);
        }
        if (_showerRoomBlock) {
            _showerRoomBlock(dic);
        }
    }
}

#pragma mark -  LKAppExpConnectListener
- (void)onConnectState:(LKAppExpConnectState)state {
    NSLog(@"长连接状态 : %@", @(state));

    if (state == LKAppExpConnectStateConnected) {
        if (!isBinded) {
            [self bindAccountWithChannel];
        }
    }
}

#pragma mark - LKAppExpDownListener

- (void)onDownstream:(NSString *_Nonnull)topic data:(id _Nullable)data {
    //NSLog(@"onDownstream topic : %@", topic);
    //NSLog(@"onDownstream data : %@", data);
    NSDictionary *replyDict = nil;
    if ([data isKindOfClass:[NSString class]]) {
        NSData *replyData = [data dataUsingEncoding:NSUTF8StringEncoding];
        replyDict = [NSJSONSerialization JSONObjectWithData:replyData options:NSJSONReadingMutableLeaves error:nil];
    } else if ([data isKindOfClass:[NSDictionary class]]) {
        replyDict = data;
    }
    if (replyDict == nil) {
        return;
    }

    NSMutableDictionary *mdic = [NSMutableDictionary dictionary];
    mdic[@"data"] = replyDict;
    mdic[@"topic"] = topic;
    {
        NSNotification *notification = [NSNotification notificationWithName:ALITHING_EVENT_ONDOWNSTREAM object:mdic userInfo:mdic];
        [[NSNotificationCenter defaultCenter] postNotification:notification];
    }

    if ([topic isEqualToString:@"/_thing/event/notify"]) {
        if ([data isKindOfClass:NSDictionary.class]) {
            //推送到通知中心
            NSDictionary *dic = (NSDictionary *)data;
            NSNotification *notification = [NSNotification notificationWithName:ALITHING_EVENT_NOTIFY object:dic userInfo:dic];
            [[NSNotificationCenter defaultCenter] postNotification:notification];
        }
        //notify 消息
        NSDictionary *value = [data objectForKey:@"value"];
        if (value) {
            NSString *operation = [value objectForKey:@"operation"];
            if (operation && [operation isEqual:@"Unbind"]) {
                //刷新列表
                [[NSNotificationCenter defaultCenter] postNotificationName:NOT_DEVICE_EDIT_SUCCESS object:nil];
            }
        }
    }

    [self analyzeDeviceData:replyDict];
}

- (BOOL)shouldHandle:(NSString *_Nonnull)topic {
    if ([topic isEqualToString:@"/thing/properties"]) {
        return YES;  //返回YES，说明对此topic感兴趣,SDK会调用[listener onDownstream:data:]
    }
    return YES;
}

#pragma mark - Channel

- (void)bindAccountWithChannel {
    //长连接通道绑定用户
    IMSCredential *credential = [[IMSCredentialManager sharedManager] credential];
    if (credential && credential.iotToken && ![credential isIotTokenExpired]) {
        [self bindChannelWithToken:credential.iotToken];
    } else {
        [[IMSCredentialManager sharedManager] asyncRefreshCredential:^(NSError *_Nullable error, IMSCredential *_Nullable credential) {
          if (credential && credential.iotToken) {
              [self bindChannelWithToken:credential.iotToken];
          } else {
              NSLog(@"移动推送请求iotToken失败:%@", error);
          }
        }];
    }
}

- (void)bindChannelWithToken:(NSString *)token {
    if (!token) {
        return;
    }

    NSString *topic = @"/account/bind";
    NSDictionary *params = @{
        @"iotToken" : token,
    };
    @weakify(self);
    [[LKAppExpress sharedInstance] invokeWithTopic:topic
                                              opts:nil
                                            params:params
                                       respHandler:^(LKAppExpResponse *_Nonnull response) {
                                         @strongify(self);
                                         if (!self) {
                                             return;
                                         }
                                         if (![response successed]) {
                                             NSLog(@"长连接通道绑定账号失败");
                                             self->isBinded = false;
                                         } else {
                                             NSLog(@"长连接通道绑定账号成功");
                                             self->isBinded = true;
                                         }
                                       }];
}

#pragma mark - Base

- (void)getBaseDataAlinkData:(BaseDataReturnBlock)returnBlock {
    self.baseDataReturnBlock = returnBlock;
}

#pragma mark - Bathtub
- (void)getBathtubAlinkData:(BathtubBlock)block {
    self.bathtubBlock = block;
}

#pragma mark - Toilet

- (void)getToiletAlinkData:(ToiletBlock)block {
    self.toiletBlock = block;
}

#pragma mark - Water Safety

- (void)getWaterSafetyAlinkData:(WaterSafetyReturnBlock)returnBlock {
    self.waterSafetyReturnBlock = returnBlock;
}

#pragma mark - Clother Stand
- (void)getClothesStandAlinkData:(ClothesStandBlock)block {
    self.clothesStandBlock = block;
}

#pragma mark - Dry Steam Room
- (void)getDrySteamRoomAlinkData:(DrySteamRoomBlock)block {
    self.drySteamRoomBlock = block;
}

#pragma mark - SmokeAlarm

- (void)getSmokeAlarmAlinkData:(SmokeAlarmBlock)block {
    self.smokeAlarmBlock = block;
}

#pragma mark - SHOWER ROOM
- (void)getShowerRoomAlinkData:(ShowerRoomBlock)block {
    self.showerRoomBlock = block;
}

#pragma mark -  reconnect

- (void)reconnect {
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    int state = (int)[[LKAppExpress sharedInstance] getMobileConnectState];
    NSLog(@"reconnect ： %@", @(state));
    if (state == 2) {
        /**
        [[LKAppExpress sharedInstance] stopConnect:^{
          dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [[LKAppExpress sharedInstance] startConnect:config connectListener:self];
            NSLog(@"reconnect ： %@", @(state));
          });
        }];
         */
        [[LKAppExpress sharedInstance] startConnect:config connectListener:self];
        NSLog(@"reconnect ： %@", @(state));
    }
}

#pragma mark - NSNotificationCenter

- (void)applicationDidBecomeActive {
    [self reconnect];
}

- (void)applicationWillResignActive {
    [[LKAppExpress sharedInstance] stopConnect:^ {
    }];
}

- (void)addNotifications {
    [self removeNotifications];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive) name:UIApplicationWillResignActiveNotification object:nil];
}

- (void)removeNotifications {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end
